use bootloader_api::BootInfo;
use bootloader_api::info::{MemoryRegionKind::Usable, Optional};
use bootloader_boot_config::LevelFilter;

pub static BOOT_LOGGER: BootLogger = BootLogger;

pub struct BootLogger;

impl BootLogger {
    pub fn init_from(&'static self, boot_info: &'static mut BootInfo) {
        let framebuffer_info;
        {
            let framebuffer = match &boot_info.framebuffer {
                Optional::None => panic!(),
                Optional::Some( fb) => fb,
            };
            framebuffer_info = framebuffer.info();
        }
        let framebuffer = match &mut boot_info.framebuffer {
            Optional::None => panic!(),
            Optional::Some( fb) => fb,
        };
        let framebuffer_slice = framebuffer.buffer_mut();
        let mut log_level = LevelFilter::Info;
        if cfg!(debug_assertions) {
            log_level = LevelFilter::Debug;
        }
        bootloader_x86_64_common::init_logger(
            framebuffer_slice,
            framebuffer_info,
            log_level,
            true,
            true);

        /*************************************************************************************
         * log BootInfo
         */
        // log memory regions
        for index in 0..boot_info.memory_regions.len() {
            if let Some(mem_region) = boot_info.memory_regions.get(index) {
                let usable = match mem_region.kind {
                    Usable => true,
                    _ => false,
                };
                log::debug!(
                    "MemoryRegion {{ index: {:04}, start: 0x{:016X}, end: 0x{:016X}, usable: {:6} }}",
                    index,
                    mem_region.start,
                    mem_region.end,
                    usable);
            }
        }
        if let Optional::Some(physical_memory_offset) = boot_info.physical_memory_offset {
            log::debug!("physical memory offset: 0x{:016X}", physical_memory_offset);
        } else {
            log::debug!("physical memory offset: None");
        }
        if let Optional::Some(recursive_offset) = boot_info.recursive_index {
            log::debug!("level-4 page table recursive index: {:04}", recursive_offset);
        } else {
            log::debug!("level-4 page table recursive index: None");
        }
        if let Optional::Some(rsdp_addr) = boot_info.rsdp_addr {
            log::debug!("ACPI RSDP data structure address: 0x{:016X}", rsdp_addr);
        } else {
            log::debug!("ACPI RSDP data structure address: None");
        }
        if let Optional::Some(tls_template) = boot_info.tls_template {
            log::debug!(
                "TlsTemplate {{ start address: 0x{:016X}, file size: {:04}, mem size: {:04} }}",
                tls_template.start_addr,
                tls_template.file_size,
                tls_template.mem_size);
        } else {
            log::debug!("TlsTemplate {{ None }}");
        }
        if let Optional::Some(ramdisk_addr) = boot_info.ramdisk_addr {
            log::debug!("ramdisk {{ address: 0x{:016X}; len: {:04} }}", ramdisk_addr, boot_info.ramdisk_len);
        } else {
            log::debug!("ramdisk {{ address: None; len: {:04} }}", boot_info.ramdisk_len);
        }
        log::debug!(
            "kernel image {{ physical address: 0x{:016X}; virtual address: 0x{:016X}; len: 0x{:04X} }}",
            boot_info.kernel_addr,
            boot_info.kernel_image_offset,
            boot_info.kernel_len);
        /*************************************************************************************/
    }
}